-
Notifications
You must be signed in to change notification settings - Fork 19.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: change to default ESM package. For developer testing and node usage in the module customization scenario. #19513
Conversation
…sage in customization module scenario.
Thanks for your contribution! The pull request is marked to be |
…sage in customization module scenario. See apache/echarts#19513
The changes brought by this PR can be previewed at: https://echarts.apache.org/examples/editor?version=PR-19513@80172d6 |
To reviewers: If this PR is going to be described in the changelog in the future release, please make sure this PR has one of the following labels: This message is shown because the PR description doesn't contain the document related template. |
How to fix the issue on the previous versions of echarts (before echarts v5.5.0), vue-echarts and other packages?The solution below works. https://github.com/100pah/amend-package npm i amend-package In package.json : {
"scripts": {
"postinstall": "npx amend-package --builtin-config fix-vue-echarts-esm.config.cjs && npx amend-package --builtin-config fix-echarts-esm.config.cjs"
}
} |
Congratulations! Your PR has been merged. Thanks for your contribution! 👍 |
Love! |
Breaking change caused by this PR (since v5.5.0)We have tried our best to make it backward compatible, but there may be something that not considered fully. The possible breaking: 1. About "file extension not specified"If using "no file extension way" to import "theme" or "i18n" or "dist" (e.g. import 'echarts/i18n/xxx') or some internal file (e.g. import xxx from 'echarts/xxx/xxx'), and the path is not listed in "exports" field of package.json, the file might not be able to find by default in some bundlers since echarts v5.5.0. Solution_1: change to import xxx from 'echarts/xxx/xxx.js' (file extension fully specified) 2. About
|
1. Brief Information
This pull request is in the type of:
2. Breaking change caused by this PR (since v5.5.0)
See #19513 (comment)
3. What does this PR do?
change to default ESM package. For developer testing and node usage in the module customization scenario.
related issues:
At present, echarts exports only esm files in npm (in
lib
dir of npm package).It works well in bundler but not well in nodejs runtime and some node-based testing framework (like vitest, jest).
This PR changes:
"type": "module"
to package.json"exports": {...}"
to package.json"type": "commonjs"
.4. Background Knowledges
4.1. How a file is recognized as ESM or CJS by nodejs runtime ?
.cjs
or.esm
, it will be recognized as CJS or ESM..js
, find the closestpackage.json
file, read"type": "module"
or"type": "commonjs"
(by default) to determine whether file is ESM or CJS.4.2. The env (runtime and bundler) we need to handle
4.3. How a package is published as both CJS and ESM
Brief:
lib
dir probably need to consider this issue. We only discuss this scenario below.[email protected]
"type": "module"
in the rootpackage.json
. This solution is not many appear."type": "module"
in the rootpackage.json
:[email protected]
,[email protected]
package.json
only contains"type": "commonjs"
in some sub-directory:[email protected]
References:
4.4. About "fully specified file extension"
CommonJS have file extension auto-completion but ESM require fully specified by default after
"type": "module"
is set topackage.json
.That is,
After
"type": "module"
is set topackage.json
, at least both nodejs and browser and some bundlers (like webpack5) follow this rule by default. It brings trouble to echarts and zrender in backward compatibility, because historically they has many internal files imported by other packages without file extension specified.See the solution in the next section "set 'exports' in package.json".
References:
4.5. Why we need to set
"exports"
in package.json"exports"
field ofpackage.json
enables packages to define which files are public and which are private. Although this mechanism is useful for a package management system, but it is not introduced for a long time in npm and the spec has been changed several times, it cause that not all runtime/bundlers fully support all the features in the current spec (consider there are legecy versions of runtime/bundlers). So if we use them, we have to be very carefully. (reference:"exports"
and"type": "module"
is supported since nodejs v12.17.0 (and unflagged conditional exports since v13.7.0, v12.17.0) (see https://nodejs.org/dist/v16.20.2/docs/api/packages.html#modules-packages)At present we add
"exports"
mainly for resolving the "file extension fully specified" issue above. (see more info about "fully specified" in the previous section.)For example, the setting below
enables
import 'echarts/core'
(file extension is not specified) to work (when"type": "module"
is set).But using
"exports"
brings some troubles when importing lots of internal files with "file extension not specified" way.Note that if
"exports"
is set, the files that are not lists in"exports"
will not be visible from outside. But historically echarts and zrender has many internal files imported by other packages (and without file extension specified).e.g.
import * as echarts 'echarts/lib/echarts'
,import 'echarts/lib/chart/line';
, ..., which are deprecated usage since v5 but widely used. And some internal utils of echarts and zrender are also been imported in that way. Currently we do not recommend that but need to keep backward compatible.The neat way to compat it is to use the subpath patterns
e.g., make
"exports"
ofpackage.json
like that:It routes all 'xxx' to 'xxx.js' and all 'xxx.js' to 'xxx.js' (rather than 'xxx.js.js').
But the spec of the subpath patterns seems to have been keeping changing. For example, at the beginning, it seem that only trailing wildcard is supported, that is, only supports
"./xxx/*": "..."
but does not support"./xxx/*.js": "..."
. It cause that some old versions of bundlers/runtimes do not support the newest spec. e.g., rollup plugin node-resovle v11.0.1 only supports wildcards at the end and do not support"./xxx/*.js": "..."
. (see impl: findExportKeyMatch and findEntrypoint ).In this situation, if setting to
{ "./*.js": "./*.js", "./*": "./*.js" }
, once"./*.js"
is not recognized,import './xxx.js';
will be resolved as./xxx.js.js
, which is not expected.if setting to
{ "./*": "./*" }
,import './xxx';
will be resolved as'./xxx'
and can not find the file because there is no file extension.Finally the only way I find is to list all the possible files in
"exports"
, ending with a{ "./*": "./*" }
.It's ugly. Is there any better idea?
Note: webpack
"exports"
since v5.0.0"exports"
since v5.13.0 (enhanced-resolve v5.6.0 Jan 12, 2021)References about compat:
4.6. Use physical entry file or alias in
"exports"
ofpackage.json
Although using
"exports"
ofpackage.json
we can make alias (or say, route) to physical file (for example:{ "exports": { "./xxx": "./yyy/zzz.js" } }
enablesimport 'echarts/xxx'
to route to'echarts/yyy/zzz.js'
), at present we can not make sure all the versions of bundle tools and runtimes in use do it consistently. So we do not use the alias setting, but keep providing physical file for each public entry. For example, for an official public entry'echarts/core'
, we provide a fileecharts/core.js
(andecharts/core.d.ts
).5. Before and After this PR
5.1. [pure nodejs]
Before this PR, echarts js like
echarts/core.js
can not be resolved as ESM. After this PR, they can.5.2. [vitest]
Before this PR vitest for vue-echarts does not work.
See:
Before this PR, we can fix the issues by patch the installed 'echarts' and 'vue-echarts':
After this PR, only 'vue-echarts' need to be patched for this case.
package.json
After 'vue-echarts' updated in future, nothing need to be patched any more.
See more details in #19513 (comment)
5.3. [jest]
echarts/core.js
can not be resolved as ESM in jest, and after this PR, can be resolved as ESM.node --experimental-vm-modules
if intending to use nodejs natively esm, because jest uses nodejs vm api, which is experimental (at least 202401). See https://github.com/jestjs/jest/blob/v29.7.0/packages/jest-resolve/src/shouldLoadAsEsm.ts#L13 and https://jestjs.io/docs/ecmascript-modules5.4. [create-react-app]
See:
create-react-app uses jest.
Event without this PR, we can also fix the issue above like that:
In
package.json
:6. Test
Have tested in:
The test cases have been put in this repo temporarily.
https://github.com/100pah/esm-boilerplate-tmp
The test cases will be committed to echarts-examples soon if the PR accepted.
7. For legacy versions of echarts
See #19513 (comment)
8. ZRender Changes
ecomfe/zrender#1051
9. Note about current "exports"
Only these entries are officially exported to users:
'echarts'
'echarts/index.js'
'echarts/index.blank.js'
'echarts/index.common.js'
'echarts/index.simple.js'
'echarts/core.js'
'echarts/charts.js'
'echarts/components.js'
'echarts/features.js'
'echarts/renderers.js'
'echarts/i18n/*
'echarts/theme/*
'echarts/types/*
'echarts/extension/*
'echarts/dist/*
'echarts/ssr/client/index.js'
The other entries listed in the
"exports"
field ofpackage.json
make the internal files visible, but they are legacy usages, not recommended but not forbidden (for the sake of keeping backward compatible). These entries are made from the search in github about which internal files are imported.